package com.benchmark.springboot.controller;

import com.benchmark.springboot.component.OkHttpAsyncClient;
import com.benchmark.springboot.enums.ErrorCodeEnum;
import com.benchmark.springboot.service.AsyncService;
import com.power.common.model.CommonResult;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * DeferredResult用例
 *
 * @author yu 2019/2/17.
 */
@Slf4j
@RestController
@RequestMapping("deferredResult")
public class DeferredResultController {


    @Resource
    private ThreadPoolTaskExecutor executor;

    @Resource
    private AsyncService asyncService;

    @Resource
    private OkHttpAsyncClient okHttpAsyncClient;

    /**
     * okHttp3异步网络请求
     *
     * @return
     */
    @GetMapping("okHttp3/asyncGet")
    public DeferredResult<String> asyncHttp() {
        String url = "https://www.baidu.com";
        DeferredResult<String> result = new DeferredResult<>();
        okHttpAsyncClient.asyncGet(url, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                result.setErrorResult("请求百度失败");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                result.setResult(response.body().string());
            }
        });
        return result;
    }

    /**
     * deferred响应
     *
     * @return
     */
    @GetMapping("/async-deferredresult")
    public DeferredResult<CommonResult<String>> handleReqDefResult() {
        log.info("Received async-deferredresult request");
        DeferredResult<CommonResult<String>> output = new DeferredResult<>();

        executor.submit(() -> {
            log.info("Processing in separate thread");
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                log.error("InterruptedException while executing the thread {}", e.fillInStackTrace());
            }
            output.setResult(CommonResult.ok());
        });

        log.info("servlet thread freed");
        return output;
    }


    /**
     * deferred响应超时
     *
     * @return
     */
    @GetMapping("/timeout")
    public DeferredResult<CommonResult<String>> timeOut() {
        log.info("外部线程：" + Thread.currentThread().getName());
        //设置超时60s
        DeferredResult<CommonResult<String>> result = new DeferredResult<>(5000L);
        result.onTimeout(() -> {
            log.info("超时啦");
            result.setResult(CommonResult.fail(ErrorCodeEnum.TIME_OUT));
        });
        result.onCompletion(() -> {
            log.info("完成咯");
        });
        executor.submit(() -> {
            log.info("副线程处理业务");
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                log.error("超时中盾");
            }
            result.setResult(CommonResult.ok().setResult("DeferredResult"));
        });
        return result;
    }

    /**
     * 异步获取数据合并返回
     *
     * @return
     * @throws Exception
     */
    @GetMapping("findUserList")
    public DeferredResult<CommonResult> findUser() throws Exception {
        log.info("执行任务");
        DeferredResult<CommonResult> deferredResult = new DeferredResult<>();
        ListenableFuture future1 = asyncService.findUser("");
        ListenableFuture future2 = asyncService.findUser("");
        ListenableFuture future3 = asyncService.findUser("");
        //等待三个线程执行完毕，如果不写下面代码接口将直接返回
        while (true) {
            if (future1.isDone() && future3.isDone() && future2.isDone()) {
                log.info("Task1 result: {}", future1.get());
                log.info("Task2 result: {}", future1.get());
                break;
            }
            Thread.sleep(1);
        }

        deferredResult.setResult(CommonResult.ok());
        return deferredResult;
    }
}
